package org.jfedor.frozenbubble;

import java.io.PrintStream;
import java.util.Random;
import java.util.Scanner;
import java.util.Vector;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.animation.Animation; 
import android.view.animation.AnimationUtils; 
import android.widget.ImageView; 
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

public class ChillOut extends Activity {
	public static long game_start_time = 0;
	public static ChillStats stats;
	public static Toast publicstaticToast;
	public class ChillThread extends Thread {
		private final long TIME_CALIBRATE = 60000;
		public final long TIME_GAME = 180000; 
		boolean playing = true;
		public void run(){
			Log.d("ChillThread", "ChillThread started.");
			Scanner calfilein;
			ChillOut.stats = new ChillStats();
			
			// Check for previous calibration data.
			try{
				Log.d("ChillCal", "Checking for previous calibration...");
				
				// Open up the calibration values
				calfilein = new Scanner(openFileInput("calibration.txt"));
				
				// Sum up the values to obtain the average
				double val = 0;
				double sum = 0;
				int count = 0;
				while(calfilein.hasNextDouble()){
					val = calfilein.nextDouble();
					Log.d("ChillCal", "Value: "+val);
					sum += val;
					count++;
				}
				ChillOut.baseline = sum / count;
				calibrating = false;
				calfilein.close();
				Log.d("ChillCal", "Calibration set! " + ChillOut.baseline);
			} catch (Exception e){
				// We don't have a baseline, set calibration mode.
				calibrating = true;
				Log.d("ChillCal", "Calibration not found. Setting calibrate mode.");
				
				ChillOut.publicstaticToast.setDuration(Toast.LENGTH_LONG);
				ChillOut.publicstaticToast.setText("First run, calibrating...");
				ChillOut.publicstaticToast.show();
			}
			
			// Main meta-loop. Controls FrozenBubble from a parallel thread.
			while(true){
				try {
					// Act once every second
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (position < readings) {
					Number GSR = fb.returnGSR();
					if ((GSR.doubleValue() > 0) && (GSR.doubleValue() < 500.0)) {
						System.out.println("Return GSR: " + GSR);
						skin_conductance[position] = GSR;
						getPeaks(position);
						position++;
					}
				}
				
				// Set the exit condition. 3 minutes for a regular game, one for calibration.
				if (!calibrating){
					if (System.currentTimeMillis()-ChillOut.game_start_time > TIME_GAME){
						Log.d("ChillEnd", "Finished three minute game.");
						
						// Show banner and wait
						/*FrozenGame fg = fb.mGameThread.mFrozenGame;
						fg.addSprite(fg.hurrySprite);
						try{
							Thread.sleep(3000);
						} catch (Exception e){
							// Didnt' sleep. Oh well.
						}*/
						
						// End game, calculate and save baseline.
						fb.finish();
						int peaks_num = ChillOut.totalPeaks();
						ChillOut.stats.setSpikes(peaks_num);
						double newBaseline = peaks_num/(TIME_GAME/1000.0);
						
						Log.d("ChillEnd", "Saving baseline: "+peaks_num+" :: "+newBaseline);
						saveCalibration(newBaseline);
						
						Intent results_intent = new Intent(ChillOut.this, ResultsActivity.class);
						startActivity(results_intent);
						//Intent results_intent = new Intent(ChillOut.this, GraphResults.class);
						//startActivity(results_intent);
						Log.d("ChillEnd", "Started results screen.");
						
						// Display Stats to log
						Log.d("ChillEnd", "Started results screen.");
						Log.d("ChillStats", "spikes       "+stats.spikes);
						Log.d("ChillStats", "lvls_total   "+stats.lvls_total);
						Log.d("ChillStats", "lvls_done    "+stats.lvls_completed);
						Log.d("ChillStats", "bbls_popped  "+stats.bbls_popped);
						Log.d("ChillStats", "bbls_shot    "+stats.bbls_launched);
						
						playing = false;
					}
				} else {
					if (System.currentTimeMillis()-ChillOut.game_start_time > TIME_CALIBRATE){
						Log.d("ChillEnd", "Done calibrating.");
						
						// Stop the game, calculate and save baseline.
						fb.finish();
						Intent results_intent = new Intent(ChillOut.this, ChillOut.class);
						startActivity(results_intent);
						int peaks_num = ChillOut.totalPeaks();
						ChillOut.stats.setSpikes(peaks_num);
						double newBaseline = peaks_num/(TIME_CALIBRATE/1000.0);
						
						Log.d("ChillEnd", "Saving baseline: "+peaks_num+" :: "+newBaseline);
						saveCalibration(newBaseline);
						
						// Display Stats to log
						Log.d("ChillEnd", "Started results screen.");
						Log.d("ChillStats", "spikes       "+stats.spikes);
						Log.d("ChillStats", "lvls_total   "+stats.lvls_total);
						Log.d("ChillStats", "lvls_done    "+stats.lvls_completed);
						Log.d("ChillStats", "bbls_popped  "+stats.bbls_popped);
						Log.d("ChillStats", "bbls_shot    "+stats.bbls_launched);
						
						playing = false;
					}
				}
				if(!playing){
					Log.d("ChillThread", "Playing no longer set. Exiting...");
					position = 0;
					increase = true;
					bottom = 0;
					top = 0;
					peaks.clear();
					calibrating = false;
					ChillOut.thread = new ChillThread();
					return;
				}

			}
		}
		
		private void saveCalibration(double newVal){
			// Try to save the new baseline to an internal file
			try{
				PrintStream calfileout = new PrintStream(openFileOutput("calibration.txt", Context.MODE_APPEND));
				calfileout.println(newVal);
				Log.d("ChillSave", "Done saving.");
			} catch (Exception e) {
				// Error writing baseline to file!
				e.printStackTrace();
			}
		}
		
		public void setToastText(String s){
			final String ss = s;
			runOnUiThread(
	                new Runnable(){
	                    public void run(){
	                    	ChillOut.publicstaticToast.setText(ss);
	                    }
	                });
		}
		
		public void setPlaying(boolean b){
			playing = b;
			ChillOut.game_start_time = System.currentTimeMillis();
		}
	}
	
	// GSR Recording variables
	public static double baseline;
	private static final double ppsThreshold = 0.0111111111;
	public static final double window = 30.0;
	
	// This method decides whether the user is at a high, low, or average stress level.
	public static int compareStress(){
		int seconds = (int)(System.currentTimeMillis() - ChillOut.game_start_time)/1000;
		System.out.println("We are calling at seconds: " + seconds);
		double peakspersec = countPeaks(seconds)/window;
		if (peakspersec+ppsThreshold < baseline) {
			Log.d("ChillStress", peakspersec+" << "+baseline);
			Log.d("ChillStress", "LOW STRESS. ");
			return -1;
		} else if (peakspersec-ppsThreshold > baseline) {
			Log.d("ChillStress", peakspersec+" >> "+baseline);
			Log.d("ChillStress", "HIGH STRESS");
			return 1;
		} else {
			Log.d("ChillStress", peakspersec+" = "+baseline);
			Log.d("ChillStress", "AVERAGE STRESS");
			return 0;
		}
	}
	
	public static boolean calibrating;
	static int position = 0;
	static boolean increase = true;
	static int bottom = 0;
	static int top = 0;
	static double threshold = 0.01;
	static int readings = 1800;
	public static Number [] skin_conductance = new Number[readings];
	public static Vector<Integer> peaks = new Vector<Integer>();	
	public static FrozenBubble fb;
	public static ChillThread thread;
	public int selection = 0;

	public static void getPeaks(int pos){
		if (pos == 0) {
			return;
		}
		else {
			if (increase) {
				if (skin_conductance[pos-1].doubleValue() < skin_conductance[pos].doubleValue()) {
					return;
				}
				else {
					top = pos-1;
					if (top == bottom) {
						bottom = pos;
						increase = false;
						return;
					}
					double slope = (skin_conductance[top].doubleValue() - skin_conductance[bottom].doubleValue())/(top - bottom);
					increase = false;
					if (slope >= threshold) {
						peaks.add(top);
					}
				}
			}
			else {
				if (skin_conductance[pos-1].doubleValue() > skin_conductance[pos].doubleValue()) {
					return;
				}
				else {
					bottom = pos-1;
					increase = true;
				}
			}
		}		
	}
	
	
	public static int countPeaks(double seconds){
		//System.out.println("countPeaks(" + seconds + ")");
		int peaks_num = 0;
		int pos = peaks.size() - 1;
		System.out.println("position " + pos);
		if ((seconds < 5.0)||(seconds > 180.0))
			return 0;
		if (peaks.isEmpty())
			return 0;
		double time_period = (seconds - 30.0)*10;
		System.out.println("time_period " + time_period);
		System.out.println("peaks.get(pos) " + peaks.get(pos));
		while ((pos >= 0) && (peaks.get(pos) > time_period)) {
			peaks_num++;
			pos--;
			System.out.println("while loop, position " + pos);
		}
		System.out.println("position " + pos);
		return peaks_num;		
	};
	
	public static int totalPeaks() {
		return peaks.size();
	};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_start_screen);
        
        thread = new ChillThread();
        
        ChillOut.publicstaticToast = Toast.makeText(getApplicationContext(), "Difficulty: " + LevelManager.currentDifficulty , Toast.LENGTH_SHORT);
        ChillOut.publicstaticToast.setText("This is a test");
        ChillOut.publicstaticToast.setGravity(Gravity.TOP, 0, 50);
        //Animations
        
        //Falling Snow
        ImageView snow1 = (ImageView)findViewById(R.id.imageView1);
        snow1.setImageResource(R.drawable.falling_snow1);
        Animation fallingSnow1 = AnimationUtils.loadAnimation(this, R.anim.falling_snow1);
        snow1.startAnimation(fallingSnow1);
        
        ImageView snow2 = (ImageView)findViewById(R.id.imageView2);
        snow2.setImageResource(R.drawable.falling_snow1);
        Animation fallingSnow2 = AnimationUtils.loadAnimation(this, R.anim.falling_snow2);
        snow2.startAnimation(fallingSnow2);
        
        //Floating Buttons
        final Button start = (Button)findViewById(R.id.startButton);
        Animation floatingS = AnimationUtils.loadAnimation(this, R.anim.floating);
        start.startAnimation(floatingS);
        
        final Button options = (Button)findViewById(R.id.optionsButton);
        Animation floatingO = AnimationUtils.loadAnimation(this, R.anim.floating);
        floatingO.setStartOffset(100);
        options.startAnimation(floatingO);
        /*
        final Button stats = (Button)findViewById(R.id.statsButton);
        Animation floatingST = AnimationUtils.loadAnimation(this, R.anim.floating);
        floatingST.setStartOffset(200);
        stats.startAnimation(floatingST);
        
        final Button achieve = (Button)findViewById(R.id.achieveButton);
        Animation floatingA = AnimationUtils.loadAnimation(this, R.anim.floating);
        floatingA.setStartOffset(300);
        achieve.startAnimation(floatingA);
         */
        final LinearLayout buttons = (LinearLayout)findViewById(R.id.linearLayout1);
        
        final Animation selected = AnimationUtils.loadAnimation(this, R.anim.selected);
        final Animation drop = AnimationUtils.loadAnimation(this, R.anim.drop);
        
        selected.setAnimationListener(new Animation.AnimationListener() { 
            public void onAnimationStart(Animation animation) { 

            	
            } 

            public void onAnimationEnd(Animation animation) { 
            	buttons.startAnimation(drop);
            } 

            public void onAnimationRepeat(Animation animation) { 

            } 

        }); 
        
        drop.setAnimationListener(new Animation.AnimationListener() { 
            public void onAnimationStart(Animation animation) { 

            } 
            public void onAnimationEnd(Animation animation) { 
            	buttons.setVisibility(LinearLayout.INVISIBLE);
            	switch(selection){
            	case 1:
				    //Game Screen
                    Intent frozen_intent = new Intent(ChillOut.this, FrozenBubble.class);
                    startActivity(frozen_intent);
                    finish();
            		break;
				case 2:
					//Options Screen
                    Intent options_intent = new Intent(ChillOut.this, OptionsActivity.class);
                    startActivity(options_intent); 
                    finish();
            		break;
            		
				case 3:
					//Stats Screen
                    Intent stats_intent = new Intent(ChillOut.this, StatsActivity.class);
                    startActivity(stats_intent); 
                    finish();
            		break;
            		
				case 4:
					//Achievements Screen
                    Intent achieve_intent = new Intent(ChillOut.this, AchieveActivity.class);
                    startActivity(achieve_intent); 
                    finish();
					deleteFile("calibration.txt");
            		break;	
            		
            	default:
            		
            		break;
            	}

            } 
            public void onAnimationRepeat(Animation animation) { 

            } 

        }); 
        
        //Start Button
        start.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {            
                start.startAnimation(selected);
                selection = 1;
           
            }
        });
        
        //Options Button
        options.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {            
                options.startAnimation(selected);
				selection = 2;
            
            }
        });
        /*
        //Stats Button
        stats.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {            
                stats.startAnimation(selected);           	
				selection = 3;
            }
        });
        
        //Achievements Button
        achieve.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {            
                achieve.startAnimation(selected);           	
				selection = 4;
            }
        });
        */
        
    }
    
    public void onClick(View v){
        Button start = (Button)findViewById(R.id.startButton);
        Animation floatingS = AnimationUtils.loadAnimation(this, R.anim.floating);
        start.startAnimation(floatingS);
    
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_start_screen, menu);
        return true;
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if ((keyCode == KeyEvent.KEYCODE_BACK))
        {
        	thread.setPlaying(false);
        	Log.d("Chill", "Back button pressed -- "+thread.playing);
            finish();
        }
        return super.onKeyDown(keyCode, event);
    }
}